<?php

class LightJob_Runner_SingleThreaded implements LightJob_IRunner
{
	/**
	 * The adapter
	 *
	 * @var LightJob_Runner_IAdapter
	 */
	private $adapter;
	
	private $jobs;
	
	public function __construct()
	{
		$this->adapter = new LightJob_Runner_Adapter_Default();
		$this->jobs = array('handles'=>array(),'descriptions'=>array());
	}
	
	public function pushJob($job)
	{
		if(!$job || !is_array($job) || !array_key_exists('mode',$job))
		{
			throw new BadFormatException("Array with key 'mode' expected, but given is: ".json_encode($job));
		}
		
		$mode = strtolower($job['mode']);
		
		$h = null;
		switch($mode)
		{
			case 'http.get' : $h = $this->adapter->pushHttpGetAction($job['action']); break;
			case 'http.post': $h = $this->adapter->pushHttpPostAction($job['action'],$job['params']); break;
			case 'cmd': $h = $this->adapter->pushCmdAction($job['action']); break;
			case 'log' : 
				$data = json_decode($job['params'],true);
				$h = $this->adapter->pushLogAction($data['txt'],$data['file'],$data['level']); break;
			case 'mail' : 
				$data = json_decode($job['params'],true);
				$h = $this->adapter->pushMailAction($data['to'],$data['from'],$data['subject'],$data['body']); break;
			case 'nop': /* nothing to do */ break;
			case 'end': throw new EndException(); break;
			default: throw new NotFoundException("Action type '$mode' does not exist");
		}
		
		if($h)
		{
			$this->jobs['handles'][] = $h;
			$this->jobs['descriptions'][] = $job;
		}
		
		return true;
	}
	
	protected function checkPending()
	{
		$read = $this->jobs['handles'];
		
        while(count($this->jobs['handles'])>0 && @stream_select($read,$write=null,$except=null,0)>0){
        	foreach($read as $fp){
            	$t = '';
                while(!feof($fp)){
                	$t.=fread($fp,1024);
                }
                stream_socket_shutdown($fp, STREAM_SHUT_RDWR);
                fclose($fp);
            }
        }

        // cleans the closed streams
        $toCleanActions = $this->jobs['handles'];
        foreach(array_keys($toCleanActions) as $i){
            if(!is_resource($toCleanActions[$i]) || feof($toCleanActions[$i])) {
            	unset($this->jobs['handles'][$i]);
            	unset($this->jobs['descriptions'][$i]);
            }
        }
		
	}
	public function pushJobs($jobs)
	{
		$this->checkPending();
		
		if(!is_array($jobs))
		{
			throw new BadFormatException("Array expected, but given is: ".json_encode($jobs));
		}
		foreach($jobs as $job)
		{
			$this->pushJob($job);
		}
		return true;
	}
	
	public function countPendingActions()
	{
		return count($this->jobs['handles']);
	}
	
	/**
	 * Sets the adapter
	 *
	 * @param LightJob_Runner_IAdapter $adapter
	 */
	public function setAdapter(LightJob_Runner_IAdapter $adapter)
	{
		$this->adapter = $adapter;
	}
	
	/**
	 * Returns the adapter
	 *
	 * @return LightJob_Runner_IAdapter
	 */
	public function getAdapter()
	{
		return $this->adapter;
	}
}
